package com.ruyuan2020.furnishing.payment.service.impl;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.ruyuan2020.common.exception.BusinessException;
import com.ruyuan2020.common.util.DateTimeUtils;
import com.ruyuan2020.furnishing.member.api.MemberApi;
import com.ruyuan2020.furnishing.member.domain.MemberDTO;
import com.ruyuan2020.furnishing.payment.constant.PaymentConstants;
import com.ruyuan2020.furnishing.payment.dao.PaymentTransactionDAO;
import com.ruyuan2020.furnishing.payment.domain.PaymentDTO;
import com.ruyuan2020.furnishing.payment.domain.PaymentTransactionDO;
import com.ruyuan2020.furnishing.payment.service.PaymentService;
import com.ruyuan2020.furnishing.thirdPay.api.ThirdPayApi;
import com.ruyuan2020.furnishing.thirdPay.domain.PayRequest;
import com.ruyuan2020.furnishing.trade.api.TradeApi;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaymentServiceImpl implements PaymentService {

    @DubboReference(version = "1.0.0")
    private MemberApi memberApi;

    @DubboReference(version = "1.0.0", cluster = "failfast", timeout = 3000)
    private TradeApi tradeApi;

    @DubboReference(version = "1.0.0", cluster = "failfast", timeout = 3000)
    private ThirdPayApi thirdPayApi;

    @Autowired
    private PaymentTransactionDAO paymentTransactionDAO;

    /**
     * 构建用于在线支付的URL
     *
     * @param paymentDTO 支付信息
     * @return 支付URL
     */
    @Override
    @Transactional
    @SentinelResource(value = "PaymentService:buildPayUrl",
            exceptionsToIgnore = BusinessException.class)
    public String buildPayUrl(PaymentDTO paymentDTO) {
        // 获取用户信息
        MemberDTO memberDTO;
        try (Entry ignored = SphU.entry("MemberApi:getMember")) {
            memberDTO = memberApi.getMember(paymentDTO.getMemberId());
        } catch (BlockException e) {
            throw new BusinessException("业务繁忙，请稍后再试");
        }
        // 创建支付信息
        PaymentTransactionDO transactionDO = new PaymentTransactionDO();
        transactionDO.setMemberId(memberDTO.getId());
        transactionDO.setMemberUsername(memberDTO.getUsername());
        transactionDO.setAmount(paymentDTO.getAmount());
        transactionDO.setPaymentMethod(paymentDTO.getPaymentMethod());
        transactionDO.setTradeNo(paymentDTO.getTradeNo());
        transactionDO.setStatus(PaymentConstants.PAYMENT_STATUS_WAIT_BUYER_PAY);
        paymentTransactionDAO.save(transactionDO);
        // 模拟调用第三方支付成功的回调
        return mockThirdPay(paymentDTO);
    }

    /**
     * 构建用于在线支付的URL
     *
     * @param resultCode 支付结果编码
     * @param tradeNo    交易记录流水号
     * @return 调用结果
     */
    @Override
    @Transactional
    @SentinelResource(value = "PaymentService:notify",
            blockHandler = "notifyBlockHandler",
            exceptionsToIgnore = BusinessException.class)
    public String notify(String resultCode, String tradeNo) {
        if ("SUCCESS".equals(resultCode)) {
            PaymentTransactionDO paymentTransactionDO = paymentTransactionDAO.getByTradeNo(tradeNo).orElseThrow(() -> new BusinessException("支付信息不存在"));
            paymentTransactionDO.setStatus(PaymentConstants.PAYMENT_STATUS_SUCCESS);
            paymentTransactionDO.setGmtFinished(DateTimeUtils.currentDateTime());
            paymentTransactionDAO.update(paymentTransactionDO);
            try (Entry ignored = SphU.entry("TradeApi:informTradeCompletedEvent")) {
                tradeApi.informTradeCompletedEvent(tradeNo);
            } catch (BlockException e) {
                throw new BusinessException("业务繁忙，请稍后再试");
            }
            return "SUCCESS";
        } else {
            // 失败处理
            return "FAILED";
        }
    }

    public String notifyBlockHandler(String resultCode, String tradeNo, BlockException ex) {
        throw new BusinessException("FAILED");
    }

    private String mockThirdPay(PaymentDTO paymentDTO) {
        try (Entry ignored = SphU.entry("PaymentService:mockThirdPay")) {
            PayRequest payRequest = new PayRequest();
            payRequest.setTradeNo(paymentDTO.getTradeNo());
            payRequest.setAmount(paymentDTO.getAmount());
            return thirdPayApi.sdkExecute(payRequest);
        } catch (BlockException e) {
            throw new BusinessException("业务繁忙，请稍后再试");
        }
    }
}
